package org.xhy.hrm.service.impl;

import com.alibaba.fastjson.JSON;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.facetoface.models.AlipayTradePrecreateResponse;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import org.checkerframework.checker.units.qual.K;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.xhy.hrm.asserts.GlobleAssert;
import org.xhy.hrm.constants.MQConstants;
import org.xhy.hrm.domain.KillOrder;
import org.xhy.hrm.domain.PayBill;
import org.xhy.hrm.dto.AlipayNotifyDto;
import org.xhy.hrm.globle.GlobleException;
import org.xhy.hrm.prop.AlipayProperties;
import org.xhy.hrm.service.IPayBillService;
import org.xhy.hrm.service.IPayService;
import org.xhy.hrm.to.PayResultTo;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
import java.util.UUID;

@Service
@Transactional
public class PayServiceImpl implements IPayService {

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private AlipayProperties alipayProperties;

    @Autowired
    private IPayBillService payBillService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public String apply(String orderNo) {
        GlobleAssert.hasText(orderNo,"无效订单号！");

        //查出订单
        KillOrder killOrder = (KillOrder) redisTemplate.opsForValue().get("order:" + orderNo);

        GlobleAssert.isNotNull(killOrder,"暂未下单成功，请等待一下啊！");

        //判断支付时间是否已经超时
        if (new Date().getTime() - killOrder.getCreateTime().getTime() > 899990){
            GlobleAssert.isNotNull(killOrder,"支付超时！");
        }


        // 1. 设置参数（全局只需设置一次）
        Factory.setOptions(alipayProperties.getOptions());
        try {
            // 2. 发起API调用（以创建当面付收款二维码为例）
            //支付单号
            String payNo = UUID.randomUUID().toString();
            BigDecimal bigDecimal = killOrder.getTotalPrice().setScale(2, BigDecimal.ROUND_HALF_UP);
            AlipayTradePagePayResponse response = Factory.Payment.Page().pay(
                    "购买的："+killOrder.getItem().getKillCourseName(),payNo,bigDecimal.toString(),alipayProperties.getReturnUrl());
            // 3. 处理响应或异常
            System.out.println("支付结果："+response.body);
            if (ResponseChecker.success(response)) {
                System.out.println("调用成功");
            } else {
                System.err.println("调用失败，原因：" + response.body);
            }

            //保存支付单
            PayBill payBill = new PayBill();
            payBill.setAmount(bigDecimal);
            //业务类型
            payBill.setBusinessType(1);
            payBill.setCreateTime(new Date());
            //详情
            payBill.setIntro(killOrder.getItem().getKillCourseName());
            payBill.setOrderNo(orderNo);
            payBill.setPayNo(payNo);
            payBill.setPayStatus(PayBill.STATE_APPLY);
            //业务对象id
            payBill.setRelationId( killOrder.getItem().getKillCourseId());
            payBillService.insert(payBill);

            //支付成功后删除redis中的秒杀订单
            redisTemplate.delete("order:" + orderNo);

            //返回html代码，给前端挑战，直接之际返回
            return response.body;
        } catch (Exception e) {
            System.err.println("调用遭遇异常，原因：" + e.getMessage());
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    @Override
    public String payNotify(AlipayNotifyDto alipayNotifyDto) throws Exception {
        //校验参数 TODO

        //验签，数字签名，防止数据在传输中被修改 JSON.toJSONString()转json字符串，JSON.parseObject（，class）装其他类型
        Map<String, String> paramsMap = JSON.parseObject(JSON.toJSONString(alipayNotifyDto),Map.class); //将异步通知中收到的所有参数都存放到map中
        boolean signVerified = Factory.Payment.Common().verifyNotify(paramsMap); //调用SDK验证签名
        GlobleAssert.isTrue(signVerified,"验签失败！！！");

        //查询订单
        String out_trade_no = alipayNotifyDto.getOut_trade_no();

        //枷锁，幂等判断
        RLock lock = redissonClient.getLock("notifylock:" + out_trade_no);
        lock.lock();
        try {
            //通过订单号查询
            PayBill payBill = payBillService.selectByPayNo(out_trade_no);
            GlobleAssert.isNotNull(payBill,"订单号无效！");
            //如果状态已经不是待处理
            if (payBill.getPayStatus() != PayBill.STATE_APPLY){
                return "success";
            }
            //再做个判断，金额是否一致
            if (payBill.getAmount().compareTo(new BigDecimal(alipayNotifyDto.getTotal_amount())) != 0){
                throw new GlobleException("金额不一致！");
            }
            //修改状态
            //如果状态还是待支付
            if (alipayNotifyDto.isTradeWit()){
                return "fail";
            }
            //如果状态是成功
            if (alipayNotifyDto.isTradeSuccess()){
                payBill.setPayStatus(PayBill.STATE_SUCCESS);
            } else if (alipayNotifyDto.isTradeExpireOrFail()){
                payBill.setPayStatus(PayBill.STATE_FAIL);
            }
            payBillService.updateById(payBill);

            //发消息到mq                                                                         待支付进不到这里，这里只要成功或者失败
            rabbitTemplate.convertAndSend(
                    MQConstants.NAME_EXCHANGE_KILL_PAY_RESULT_TOPIC,
                    "killresult.pay",new PayResultTo(payBill.getOrderNo(),payBill.getPayStatus() == PayBill.STATE_SUCCESS)

            );
        } finally {
            if (lock.isLocked()){
                lock.unlock();
            }
        }
        return null;
    }
}
